from flask import abort
from flask import current_app, jsonify,render_template
from flask import g
from flask import request

from info import db
from info.models import News, User, Comment, CommentLike
from info.utils.commons import user_login_data
from info.utils.response_code import RET
from . import news_blue

# 功能:关注
# 请求路径: /news/followed_user
# 请求方式: POST
# 携带参数: news_id,action
# 返回值: errno,errmsg
@news_blue.route('/followed_user', methods=['POST'])
@user_login_data
def followed_user():
    """
    1.判断用户是否登陆
    2.获取参数
    3.参数校验.为空校验
    4.操作类型校验
    5.根据作者编号取出作者对象,判断作者是否存在
    7.根据操作类型.进行关注或者取消关注
    8.返回响应
       """
    # 1.判断用户是否登陆
    if not g.user:
        return jsonify(errno=RET.NODATA, errmsg="用户未登录")

    # 2.获取参数
    author_id = request.json.get("user_id")
    action = request.json.get("action")

    # 3.参数校验.为空校验
    if not all([author_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不全")

    # 4.操作类型校验
    if not action in ["follow", "unfollow"]:
        return jsonify(errno=RET.DATAERR, errmsg="操作类型有误")

    # 5.根据作者编号取出作者对象,判断作者是否存在
    try:
        author = User.query.get(author_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="作者获取失败")

    if not author:
        return jsonify(errno=RET.NODATA, errmsg="作则不存在")

    # 7.根据操作类型.进行关注或者取消关注
    if action == 'follow':
        # 7.1 判断用户是否有关注作者
        if not g.user in author.followers:
            author.followers.append(g.user)
    else:
        # 7.1 判断用户是否有该新闻做过收藏
        if g.user in author.followers:
            author.followers.remove(g.user)

    # 8.返回响应
    return jsonify(errno=RET.OK, errmsg="操作成功")


# 功能:评论点赞
# 请求路径: /news/comment_like
# 请求方式: POST
# 携带参数: news_id,comment_id,action,g.user
# 返回值: errno,errmsg
@news_blue.route('/comment_like', methods=['POST'])
@user_login_data
def comment_like():
    """
    # 1.判断用户是否登陆
    # 2.获取参数
    # 3.参数校验,为空校验
    # 4.参数类型校验
    # 5.通过通过评论编号查询对象,判断是否存在
    # 6.根据操作类型点赞取消点赞
    # 7.返回响应
    """
    # 1.判断用户是否登陆
    if not g.user:
        return jsonify(errno=RET.NODATA,errmsg="用户未登陆")

    # 2.获取参数
    comment_id = request.json.get("comment_id")
    action = request.json.get("action")

    # 3.参数校验,为空校验
    if not all([comment_id,action]):
        return jsonify(errno=RET.PARAMERR,errmsg="参数不全")

    # 4.参数类型校验
    if not action in ["add","remove"]:
        return jsonify(errno=RET.DATAERR, errmsg="操作类型有误")

    # 5.通过通过评论编号查询对象,判断是否存在
    try:
        comment = Comment.query.get(comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg="获取评论失败")

    if not comment: return jsonify(errno=RET.NODATA,errmsg="评论不存在")

    # 6.根据操作类型点赞取消点赞
    try:
        if action == "add":
            # 判断用户是否有对该评论点过赞
            comment_like = CommentLike.query.filter(CommentLike.user_id == g.user.id,
                                                    CommentLike.comment_id == comment_id).first()
            if not comment_like:
                # 创建点赞对象
                comment_like = CommentLike()
                comment_like.user_id = g.user.id
                comment_like.comment_id = comment_id

                # 添加到数据库中
                db.session.add(comment_like)

                # 将该评论的点赞数量加1
                comment.like_count += 1
                db.session.commit()
        else:
            # 判断用户是否有对该评论点过赞
            comment_like = CommentLike.query.filter(CommentLike.user_id == g.user.id,
                                                    CommentLike.comment_id == comment_id).first()
            if comment_like:
                # 创建点赞对象
                db.session.delete(comment_like)

                # 将该评论的点赞数量减一
                if comment.like_count > 0:
                    comment.like_count -= 1
                db.session.commit()
    except Exception as e:
        current_app.logger.error(e)


    # 7.返回响应
    return jsonify(errno=RET.OK,errmsg="操作成功")


# 功能:新闻评论
# 请求路径: /news/news_comment
# 请求方式: POST
# 携带参数: news_id,comment,parent_id,g.user
# 返回值: errno,errmsg,评论字典
@news_blue.route('/news_comment', methods=['POST'])
@user_login_data
def news_comment():
    """
    1.判断用户是否登陆
    2.获取参数
    3.校验参数,为空校验
    4.根据新闻id获取到新闻对象,判断新闻对象是否存在
    5.创建评论对象,设置属性
    6.保存评论到数据库中
    7.返回响应,携带评论的数据
    """
    # 1.判断用户是否登陆
    if not g.user:
        return jsonify(errno=RET.NODATA, errmsg="用户未登录")

    # 2.获取参数
    news_id = request.json.get("news_id")
    content = request.json.get("comment")
    parent_id = request.json.get("parent_id")

    # 3.校验参数,为空校验
    if not all([news_id,content]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不全")

    # 4.根据新闻id获取到新闻对象,判断新闻对象是否存在
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="获取新闻失败")

    if not news: return jsonify(errno=RET.NODATA,errmsg="新闻不存在")

    # 5.创建评论对象,设置属性
    comment = Comment()
    comment.user_id = g.user.id
    comment.news_id = news_id
    comment.content = content
    if parent_id:
        comment.parent_id = parent_id

    # 6.保存评论到数据库中
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="存储失败")

    # 7.返回响应,携带评论的数据
    return jsonify(errno=RET.OK,errmsg="评论成功",data=comment.to_dict())


# 功能:收藏新闻
# 请求路径: /news/news_collect
# 请求方式: POST
# 携带参数: news_id,action,g.user
# 返回值: errno,errmsg
@news_blue.route('/news_collect',methods=["POST"])
@user_login_data
def news_collect():
    """
    1.判断用户是否登陆
    2.获取参数
    3.参数校验.为空校验
    4.操作类型校验
    5.根据新闻编号取出新闻对象
    6.判断新闻是否存在
    7.根据操作类型.进行收藏或者取消收藏
    8.返回响应
    """
    # 1.判断用户是否登陆
    if not g.user:
        return jsonify(errno=RET.NODATA, errmsg="用户未登录")

    # 2.获取参数
    news_id = request.json.get("news_id")
    action = request.json.get("action")

    # 3.参数校验.为空校验
    if not all([news_id,action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不全")

    # 4.操作类型校验
    if not action in ["collect","cancel_collect"]:
        return jsonify(errno=RET.DATAERR, errmsg="操作类型有误")

    # 5.根据新闻编号取出新闻对象
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="新闻获取失败")

    # 6.判断新闻是否存在
    if not news:
        return jsonify(errno=RET.NODATA, errmsg="新闻不存在")

    # 7.根据操作类型.进行收藏或者取消收藏
    if action == 'collect':
        # 7.1 判断用户是否有该新闻做过收藏
        if not news in g.user.collection_news:
            g.user.collection_news.append(news)
    else:
        # 7.1 判断用户是否有该新闻做过收藏
        if news in g.user.collection_news:
            g.user.collection_news.remove(news)

    # 8.返回响应
    return jsonify(errno=RET.OK, errmsg="操作成功")



# 功能:展示新闻
# 请求路径: /passport/<int:news_id>
# 请求方式: GET
# 携带参数: news_id
# 返回值: detail.html页面,用户data字典数据
@news_blue.route('/<int:news_id>')
@user_login_data
def news_detail(news_id):

    # 1.根据新闻编号,查出新闻对象
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="获取新闻失败")

    # 2.如果news不存在,抛出异常
    if not news:
        abort(404)

    # 3.获取6条热们新闻
    try:
        click_news = News.query.order_by(News.clicks.desc()).limit(6).all()
    except Exception as e:
        current_app.logger.error(e)


    # 4.将新闻的对象列表,转换成字典列表

    click_news_list = []
    for new in click_news:
        click_news_list.append(new.to_dict())

    # 5.判断用户是否收藏过该新闻
    is_collected = False
    # 用户需要登陆,以及在用户收藏新闻列表中
    if g.user:
        if news in g.user.collection_news:
            is_collected = True

    # 6.查询该新闻的所有评论内容
    try:

        comments = Comment.query.filter(Comment.news_id == news_id).order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="获取评论失败")

    # 6.1用户点赞过的评论编号
    try:
        # 6.1.1 还用户点过的所有赞
        commentlikes = []
        if g.user:
            commentlikes = CommentLike.query.filter(CommentLike.user_id == g.user.id).all()

        # 6.1.2 获取该用户点赞过的评论编号
        mylike_comment_ids = []
        for commentlike in commentlikes:
            mylike_comment_ids.append(commentlike.comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取点赞失败")

    # 7.将评论列表转成字典列表
    comments_list =[]
    for comment in comments:
        # 将平困对象转字典
        conn_dict = comment.to_dict()

        # 添加key ,value记录点赞
        conn_dict["is_like"] = False

        # 判断用户是否对评论点过赞
        if g.user and comment.id in mylike_comment_ids:
            conn_dict["is_like"] = True

        comments_list.append(conn_dict)

    # 7.判断登陆的用户是否关注了新闻的作者
    is_followed = False
    if g.user and news.user:
        if g.user in news.user.followers:
            is_followed = True

    # 8.携带数据,渲染页面
    data = {
        "new_info":news.to_dict(),
        "user_info":g.user.to_dict() if g.user else "",
        "news":click_news_list,
        "is_collected": is_collected,
        "comments":comments_list,
        "is_followed":is_followed
    }

    # 8.判断用户是否关注了新闻的作者

    return render_template("news/detail.html",data=data)